package cn.actoncode.boot.framework.common.util.date;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 时间工具类
 *
 * @author bin
 */
@Slf4j
public class DateUtils {

    /**
     * 时区 - 默认
     */
    public static final String TIME_ZONE_DEFAULT = "GMT+8";

    /**
     * 秒转换成毫秒
     */
    public static final long SECOND_MILLIS = 1000;

    public static final String FORMAT_YEAR_MONTH_DAY = "yyyy-MM-dd";

    public static final String FORMAT_YEAR_MONTH_DAY_HOUR = "yyyy-MM-dd HH";

    public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE = "yyyy-MM-dd HH:mm";

    public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss";

    public static final String FORMAT_YEAR_MONTH_DAY_T_HOUR_MINUTE_SECOND_Z = "yyyy-MM-dd'T'HH:mm:ss Z";

    public static final String FORMAT_HOUR_MINUTE_SECOND = "HH:mm:ss";

    /***
     * 时间类型枚举
     */
    public enum Field {
        /**
         * 年
         */
        YEAR,
        /**
         * 月
         */
        MONTH,
        /**
         * 天
         */
        DAY,
        /**
         * 时
         */
        HOUR,
        /**
         * 分
         */
        MINUTE,
        /**
         * 秒
         */
        SECOND,
        /**
         * 毫秒
         */
        MILLISECOND

    }

    /**
     * 添加时间
     *
     * @param duration        时间
     * @return 日期
     */
    public static Date addTime(Duration duration) {
        return new Date(System.currentTimeMillis() + duration.toMillis());
    }

    /**
     * 是否过期
     *
     * @param time        时间
     * @return 是否过期
     */
    public static boolean isExpired(Date time) {
        return System.currentTimeMillis() > time.getTime();
    }

    /**
     * 相差的毫秒数
     *
     * @param endTime        结束时间
     * @param startTime      开始时间
     * @return 是否过期
     */
    public static long diff(Date endTime, Date startTime) {
        return endTime.getTime() - startTime.getTime();
    }


    /**
     * 创建指定时间
     *
     * @param year        年
     * @param mouth       月
     * @param day         日
     * @return 指定时间
     */
    public static Date buildTime(int year, int mouth, int day) {
        return buildTime(year, mouth, day, 0, 0, 0);
    }

    /**
     * 创建指定时间
     *
     * @param year        年
     * @param mouth       月
     * @param day         日
     * @param hour        小时
     * @param minute      分钟
     * @param second      秒
     * @return 指定时间
     */
    public static Date buildTime(int year, int mouth, int day,
                                 int hour, int minute, int second) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, mouth - 1);
        calendar.set(Calendar.DAY_OF_MONTH, day);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        calendar.set(Calendar.MILLISECOND, 0); // 一般情况下，都是 0 毫秒
        return calendar.getTime();
    }

    /**
     *  获取两时间最大的时间
     *
     * @param a
     * @param b
     **/
    public static Date max(Date a, Date b) {
        if (a == null) {
            return b;
        }
        if (b == null) {
            return a;
        }
        return a.compareTo(b) > 0 ? a : b;
    }

    /**
     * 是否在当前时间之前
     *
     * @param date
     **/
    public static boolean beforeNow(Date date) {
        return date.getTime() < System.currentTimeMillis();
    }

    /**
     * 是否在当前时间后
     *
     * @param date
     **/
    public static boolean afterNow(Date date) {
        return date.getTime() >= System.currentTimeMillis();
    }

    /**
     * 计算当期时间相差的日期
     *
     * @param field  日历字段.<br/>eg:Calendar.MONTH,Calendar.DAY_OF_MONTH,<br/>Calendar.HOUR_OF_DAY等.
     * @param amount 相差的数值
     * @return 计算后的日志
     */
    public static Date addDate(int field, int amount) {
        return addDate(null, field, amount);
    }

    /**
     * 计算当期时间相差的日期
     *
     * @param date   设置时间
     * @param field  日历字段 例如说，{@link Calendar#DAY_OF_MONTH} 等
     * @param amount 相差的数值
     * @return 计算后的日志
     */
    public static Date addDate(Date date, int field, int amount) {
        if (amount == 0) {
            return date;
        }
        Calendar c = Calendar.getInstance();
        if (date != null) {
            c.setTime(date);
        }
        c.add(field, amount);
        return c.getTime();
    }

    /***
     * 返回枚举指定的日期类型
     *
     * @param date  日期
     * @param field 日期类型
     * @return int
     */
    public static int get(Date date, Field field) {

        Calendar ca = Calendar.getInstance();
        ca.setTime(date);
        switch (field) {
            case YEAR:
                return ca.get(Calendar.YEAR);
            case MONTH:
                return ca.get(Calendar.MONTH) + 1;
            case DAY:
                return ca.get(Calendar.DAY_OF_MONTH);
            case HOUR:
                return ca.get(Calendar.HOUR_OF_DAY);
            case MINUTE:
                return ca.get(Calendar.MINUTE);
            case SECOND:
                return ca.get(Calendar.SECOND);
            case MILLISECOND:
                return ca.get(Calendar.MILLISECOND);
            default:
                return 0;
        }

    }

    /***
     * 转换为日期
     *
     * @param dateStr 日期字符串
     * @return Date
     */
    public static Date toDate(String dateStr) {
        String format = null;
        switch (dateStr.length()) {
            case 7:
                format = "yyyy-MM";
                break;
            case 6:
                format = "yyMMdd";
                break;
            case 8:
                format = "yyyyMMdd";
                break;
            case 10:
                format = dateStr.indexOf("-") > 0 ? "yyyy-MM-dd" : "yyyyMMddHH";
                break;
            case 12:
                format = "yyyyMMddHHmm";
                break;
            case 14:
                format = "yyyyMMddHHmmss";
                break;
            case 17:
                format = "yyyyMMddHHmmssSSS";
                break;
            case 19:
                format = "yyyy-MM-dd HH:mm:ss";
                break;
            case 25:
                format = "yyyy-MM-dd'T'HH:mm:ssX";
                break;
            default:
                return null;
        }

        return DateUtils.convert(dateStr, format);
    }

    /**
     * 取得给定日期的凌晨0:00时间
     *
     * @param date 日期
     * @return String
     */
    public static Date getDateFirst(Date date) {
        Calendar ca = Calendar.getInstance();
        ca.setTime(date);
        Calendar calfirstday = new GregorianCalendar(ca.get(Calendar.YEAR), ca.get(Calendar.MONTH),
                ca.get(Calendar.DAY_OF_MONTH));
        return calfirstday.getTime();
    }

    /**
     * 指定格式,获取当前时间的字符串形式
     *
     * @param format 格式
     * @return String
     */
    public static String getCurrentDT(String format) {
        String res = "";
        try {
            Date date = new Date();
            SimpleDateFormat sf = new SimpleDateFormat(format);

            res = sf.format(date);
        } catch (Exception ex) {
            log.error("", ex);
        }
        return res;
    }

    /**
     * 取得给定日期相差n月的第一天凌晨0:00时间<br/>
     * 1 n可以为负值或0,分别取之前的月份或指定月份
     *
     * @param date 日期
     * @param n    月份
     * @return Date
     */
    public static Date getMonthFirst(Date date, int n) {
        Calendar ca = Calendar.getInstance();
        ca.setTime(date);
        Calendar calfirstday = new GregorianCalendar(ca.get(Calendar.YEAR), ca.get(Calendar.MONTH) + n, 1);
        return calfirstday.getTime();
    }

    /**
     * 取得当月第一天凌晨0:00时间
     *
     * @return Date
     */
    public static Date getThisMonthFirst() {
        Calendar cal = Calendar.getInstance();
        Calendar calfirstday = new GregorianCalendar(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 1);
        return calfirstday.getTime();
    }

    /**
     * 取得某个月凌晨0:00时间
     *
     * @param date 日期
     * @return Date
     */
    public static Date getMonthFirst(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, 0);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        return cal.getTime();
    }

    /**
     * 取得某个月最后一天 最后一分一秒
     *
     * @param date 日期
     * @return Date
     */
    public static Date getMonthLast(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, 1);
        //cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        return cal.getTime();
    }


    /**
     * 取得下一天的凌晨00:00:00时间
     *
     * @return Date
     */
    public static Date getNextDay() {
        Calendar cal = Calendar.getInstance();
        Calendar calDay = new GregorianCalendar(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
                cal.get(Calendar.DAY_OF_MONTH) + 1);
        calDay.add(Calendar.HOUR_OF_DAY, 0);
        calDay.add(Calendar.MINUTE, 0);
        calDay.add(Calendar.SECOND, 0);
        return calDay.getTime();
    }

    /**
     * 取得今天凌晨00:00:00时间
     *
     * @return Date
     */
    public static Date getToday() {
        Calendar cal = Calendar.getInstance();
        Calendar calDay = new GregorianCalendar(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
                cal.get(Calendar.DAY_OF_MONTH));
        calDay.add(Calendar.HOUR_OF_DAY, 0);
        calDay.add(Calendar.MINUTE, 0);
        calDay.add(Calendar.SECOND, 0);
        return calDay.getTime();
    }

    /**
     * 取得今天晚上23:59:59时间
     *
     * @return Date
     */
    public static Date getTodayEnd() {
        Calendar cal = Calendar.getInstance();
        Calendar calDay = new GregorianCalendar(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
                cal.get(Calendar.DAY_OF_MONTH));
        calDay.add(Calendar.HOUR_OF_DAY, 23);
        calDay.add(Calendar.MINUTE, 59);
        calDay.add(Calendar.SECOND, 59);
        return calDay.getTime();
    }

    /**
     * 取当前小时的0分0秒的时间
     *
     * @param date 日期
     * @return Date
     */
    public static Date getHourFirst(Date date) {
        if (date == null) {
            return null;
        }
        Calendar ca = Calendar.getInstance();
        ca.setTime(date);
        ca.set(Calendar.MINUTE, 0);
        ca.set(Calendar.SECOND, 0);
        ca.set(Calendar.MILLISECOND, 0);
        return ca.getTime();
    }

    /**
     * 取当前分钟的0秒的时间
     *
     * @param date 日期
     * @return Date
     */
    public static Date getMinuteFirst(Date date) {
        if (date == null) {
            return null;
        }
        Calendar ca = Calendar.getInstance();
        ca.setTime(date);
        ca.set(Calendar.SECOND, 0);
        ca.set(Calendar.MILLISECOND, 0);
        return ca.getTime();
    }

    /**
     * 取得下一天的时间字符串
     *
     * @param date 日期
     * @return Date
     */
    public static String getNextDay(String date) {

        SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_YEAR_MONTH_DAY);
        Calendar cal = Calendar.getInstance();
        try {
            cal.setTime(sdf.parse(date));
        } catch (ParseException e) {
            log.error("Exception:", e);
        }
        cal.add(Calendar.DAY_OF_MONTH, 1);
        return sdf.format(cal.getTime());
    }

    /***
     * 获取下一天
     *
     * @param date 日期
     * @return date
     */
    public static Date getNextDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DAY_OF_MONTH, 1);
        return cal.getTime();
    }


    /**
     * 字符串转化成日期
     *
     * @param date 日期字符串
     * @return date
     */
    public static Date convert(String date) {
        Date retValue = null;
        SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_YEAR_MONTH_DAY);
        try {
            retValue = sdf.parse(date);
        } catch (ParseException e) {
            log.error("", e);
        }
        return retValue;
    }

    /***
     * 日期转换
     *
     * @param date   日期字符串
     * @param format 转换格式
     * @return date
     */
    public static Date convert(String date, String format) {
        Date retValue = null;
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try {
            retValue = sdf.parse(date);
        } catch (ParseException e) {
            log.error("字符串转日期失败", e);
        }
        return retValue;
    }

    /***
     * 日期转换
     *
     * @param date   日期字符串
     * @param format 转换格式
     * @return date
     */
    public static Date convertTZ(String date, String format) {
        Date retValue = null;
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        date = date.replace("Z", " UTC");//UTC是本地时间

        try {
            retValue = sdf.parse(date);
        } catch (ParseException e) {
            log.error("字符串转日期失败", e);
        }
        return retValue;
    }

    /***
     * 日期转换
     *
     * @param date 日期字符串
     * @return date
     */
    public static Date convert1(String date) {
        Date retValue = null;
        SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND);
        try {
            retValue = sdf.parse(date);
        } catch (ParseException e) {
            log.error("", e);
        }
        return retValue;
    }

    /***
     * 日期转换
     *
     * @param date 日期格式
     * @return date
     */
    public static Date convert2(String date) {
        Date retValue = null;
        SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_HOUR_MINUTE_SECOND);
        try {
            retValue = sdf.parse(date);
        } catch (ParseException e) {
            log.error("", e);
        }
        return retValue;
    }

    /***
     * 日期转换
     *
     * @param date 日期字符串
     * @return date
     */
    public static Date convert3(String date) {
        Date retValue = null;
        SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_YEAR_MONTH_DAY_HOUR);
        try {
            retValue = sdf.parse(date);
        } catch (ParseException e) {
            log.error("", e);
        }
        return retValue;
    }

    /**
     * 日期转化成字符串
     *
     * @param date   日期格式
     * @param format 转换格式
     * @return String
     */
    public static String convert(Date date, String format) {
        if (null == date) {
            return "";
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }

    /**
     * 取得与今天相隔plus天凌晨0:00时间
     *
     * @param plus 天数
     * @return date
     */
    public static Date getDateFromToday(int plus) {
        Calendar cal = Calendar.getInstance();
        Calendar calnextday = new GregorianCalendar(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
                cal.get(Calendar.DAY_OF_MONTH) + plus);
        return calnextday.getTime();
    }

    /****
     * 取得与今天相隔plus天晚上23:59:59时间, add by wahehe
     * @param plus 天数
     * @return
     */
    public static Date getLastDateFromToday(int plus) {
        Date date = getDateFromToday(plus);
        date = addDateHours(date, 23);
        date = addDateMinutes(date, 59);
        date = addDateSeconds(date, 59);
        return date;
    }

    /****
     * 取得传入时间的加减天、小时，分钟，秒后的时间
     * @param date 传入的时间
     * @param days 天数
     * @param hours 小时
     * @param minutes 分钟
     * @param seconds 秒
     * @return
     */
    public static Date addTime(Date date, int days, int hours, int minutes, int seconds) {
        if (null == date) {
            return null;
        }
        date = addDateDays(date, days);
        date = addDateHours(date, hours);
        date = addDateMinutes(date, minutes);
        date = addDateSeconds(date, seconds);
        return date;
    }

    /****
     * 设置传入时间的时分秒
     * @param date 传入时间
     * @param hours 时
     * @param minutes 分
     * @param seconds 秒
     * @return
     */
    public static Date setDateTime(Date date, int hours, int minutes, int seconds) {
        if (null == date) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, hours);
        calendar.set(Calendar.MINUTE, minutes);
        calendar.set(Calendar.SECOND, seconds);
        return calendar.getTime();
    }

    /***
     * 当前天数加上小时
     *
     * @param plus 小时
     * @return date
     */
    public static Date getDateFromTodayByHour(int plus) {

        Calendar cal = Calendar.getInstance();
        Calendar calnextday = new GregorianCalendar(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
                cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.HOUR_OF_DAY) + plus, 0);
        return calnextday.getTime();
    }


    /**
     * 取得list中比默认值小的最小date,null认为最大,全比默认值大，返回默认值
     *
     * @param dateList    日期集合
     * @param defaultDate 默认值
     * @return date
     */
    public static Date getMinDateByList(List<Date> dateList, Date defaultDate) {
        Date tempDate = defaultDate;
        for (int i = 0; i < dateList.size(); i++) {
            if (dateList.get(i) == null) {
                continue;
            }
            if (dateList.get(i).getTime() < tempDate.getTime()) {
                tempDate = dateList.get(i);
            }
        }
        return tempDate;
    }

    /**
     * 两个日期相差天数
     *
     * @param date1 日期
     * @param date2 日期
     * @return 天数
     */
    public static int getDiffDays(Date date1, Date date2) {

        return (int) ((date1.getTime() - date2.getTime()) / (1000 * 60 * 60 * 24));
    }

    /**
     * 两个日期相差小时数
     *
     * @param date1 日期
     * @param date2 日期
     * @return 小时数
     */
    public static int getDiffHours(Date date1, Date date2) {

        return (int) ((date1.getTime() - date2.getTime()) / (1000 * 60 * 60));
    }

    /**
     * 两个日期相差分钟数
     *
     * @param date1 日期
     * @param date2 日期
     * @return 分钟数
     */
    public static int getDiffMinute(Date date1, Date date2) {

        return (int) ((date1.getTime() - date2.getTime()) / (1000 * 60));
    }


    /***
     * 计算两个日期之间的天数
     *
     * @param early 日期
     * @param late  日期
     * @return int
     */
    public static int daysOfTwo(Date early, Date late) {
        int count = 0;
        if (early == null || late == null) {
            return count;
        }
        Calendar calst = Calendar.getInstance();
        Calendar caled = Calendar.getInstance();
        calst.setTime(early);
        caled.setTime(late);
        // 设置时间为0时
        calst.set(Calendar.HOUR_OF_DAY, 0);
        calst.set(Calendar.MINUTE, 0);
        calst.set(Calendar.SECOND, 0);
        caled.set(Calendar.HOUR_OF_DAY, 0);
        caled.set(Calendar.MINUTE, 0);
        caled.set(Calendar.SECOND, 0);
        // 得到两个日期相差的天数
        int days = ((int) (caled.getTime().getTime() / 1000) - (int) (calst.getTime().getTime() / 1000)) / 3600 / 24;
        return days;
    }


    /***
     * 日期比较返回最小日期
     *
     * @param date1 日期
     * @param date2 日期
     * @return date
     */
    public static Date minDate(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
            return null;
        }
        Calendar ca = Calendar.getInstance();
        ca.setTime(date1);
        int day1 = ca.get(Calendar.DAY_OF_YEAR);
        ca.setTime(date2);
        int day2 = ca.get(Calendar.DAY_OF_YEAR);
        return day1 > day2 ? date2 : date1;
    }


    /***
     * 比较日期大小，如果有个日期为空。返回false
     *
     * @param d1 日期
     * @param d2 日期
     * @return true/false
     */
    public static boolean compareDate(Date d1, Date d2) {
        if (d1 != null && d2 != null) {
            Calendar ca = Calendar.getInstance();
            ca.setTime(d1);
            int day1 = ca.get(Calendar.DAY_OF_YEAR);
            ca.setTime(d2);
            int day2 = ca.get(Calendar.DAY_OF_YEAR);
            return day1 > day2;
        }
        return false;
    }

    /***
     * 在当前日期上加多少月
     *
     * @param date   日期
     * @param months 需要加的月份
     * @return date
     */
    public static Date addDateMonths(Date date, int months) {
        if (date == null) {
            return null;
        }
        Calendar ca = Calendar.getInstance();
        ca.setTime(date);
        ca.add(Calendar.MONTH, months);
        return ca.getTime();
    }


    /***
     * 在当前日期上加多少天
     *
     * @param date 日期
     * @param days 天数
     * @return date
     */
    public static Date addDateDays(Date date, int days) {
        if (date == null) {
            return null;
        }
        Calendar ca = Calendar.getInstance();
        ca.setTime(date);
        ca.add(Calendar.DAY_OF_YEAR, days);
        return ca.getTime();
    }


    /***
     * <p>在当前日期上减多少天 <p/>
     *
     * @param date 日期
     * @param days 相加的天数
     * @return date
     */
    public static Date delDateDays(Date date, int days) {
        if (date == null) {
            return null;
        }
        Calendar ca = Calendar.getInstance();
        ca.setTime(date);
        ca.add(Calendar.DAY_OF_YEAR, -days);
        return ca.getTime();
    }

    /***
     * 在当前日期上加多少小时
     *
     * @param date  日期
     * @param hours 小时
     * @return date
     */
    public static Date addDateHours(Date date, int hours) {
        if (date == null) {
            return null;
        }
        Calendar ca = Calendar.getInstance();
        ca.setTime(date);
        ca.add(Calendar.HOUR_OF_DAY, hours);
        return ca.getTime();
    }

    /***
     * 在当前日期上加多少分钟
     *
     * @param date    日期
     * @param minutes 分钟
     * @return date
     */
    public static Date addDateMinutes(Date date, int minutes) {
        if (date == null) {
            return null;
        }
        Calendar ca = Calendar.getInstance();
        ca.setTime(date);
        ca.add(Calendar.MINUTE, minutes);
        return ca.getTime();
    }

    /**
     * 在当前日期上加多少秒
     */
    /***
     * @param date     日期
     * @param senconds 秒
     * @return date
     */
    public static Date addDateSeconds(Date date, int senconds) {
        if (date == null) {
            return null;
        }
        Calendar ca = Calendar.getInstance();
        ca.setTime(date);
        ca.add(Calendar.SECOND, senconds);
        return ca.getTime();
    }

    /***
     * 是否为日期类型
     *
     * @param s          字符串
     * @param formatType 格式
     * @return date
     */
    public static boolean isRightDate(String s, String formatType) {
        boolean b = true;
        SimpleDateFormat simpledateformat = new SimpleDateFormat(formatType);
        try {
            simpledateformat.parseObject(s);
        } catch (Exception ex) {
            b = false;
        }
        return b;
    }

    /***
     * 当前日期字符串
     *
     * @return String
     */
    public static String nowDateTime() {
        String s = "";
        try {
            Date date = new Date();
            SimpleDateFormat simpledateformat = new SimpleDateFormat("yyyyMMddHHmmss");
            s = simpledateformat.format(date);
        } catch (Exception ex) {
            log.error("", ex);
        }
        return s;
    }

    /**
     * 获取当前日期是周几<br>
     *
     * @param dt  日期
     * @param isS 是否返回为String 格式
     * @return 当前日期是星期几
     */
    public static String weekOfDate(Date dt, boolean isS) {
        String[] weekDays = { "周日", "周一", "周二", "周三", "周四", "周五", "周六"};
        Calendar cal = Calendar.getInstance();
        cal.setTime(dt);
        int index = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (isS) {
            return weekDays[index];
        }
        return index + "";
    }

    /**
     * 获取当前小时
     *
     * @param dt 日期
     * @return int
     */
    public static int hourOfDate(Date dt) {
        int hour = -1;
        if (dt != null) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(dt);
            hour = cal.get(Calendar.HOUR_OF_DAY);
        }
        return hour;
    }

    /**
     * 获取当前分钟
     *
     * @param dt 日期
     * @return int
     */
    public static int minuteOfDate(Date dt) {
        int minute = -1;
        if (dt != null) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(dt);
            minute = cal.get(Calendar.MINUTE);
        }
        return minute;
    }

    /**
     * 获取当前秒钟
     *
     * @param dt 日期
     * @return int
     */
    public static int secondOfDate(Date dt) {
        int second = -1;
        if (dt != null) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(dt);
            second = cal.get(Calendar.SECOND);
        }
        return second;
    }

    /**
     * 返回当前时间是这一年中第几周
     *
     * @param dt 日期
     * @return int
     */
    public static int weekOfYear(Date dt) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(dt);
        int w = cal.get(Calendar.WEEK_OF_YEAR);
        return w;
    }

    /***
     * 日期是否在合法的范围内
     *
     * @param compareDate 待比较时间
     * @param startDate   起点时间
     * @param endDate     结束时间
     * @return true/false
     */
    public static boolean isBetween(Date compareDate, Date startDate, Date endDate) {
        return (compareDate.compareTo(startDate) >= 0 && compareDate.compareTo(endDate) <= 0);
    }

    /**
     * 时间戳转时间字符串
     *
     * @param time 时间戳
     * @return String
     */
    public static String getDateString(Long time) {
        SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND);

        return sdf.format(time);
    }

    /**
     * 时间戳转时间字符串
     *
     * @param time 时间戳
     * @return String
     */
    public static String getDateString2(Long time) {
        SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_YEAR_MONTH_DAY);

        return sdf.format(time);
    }
    /**
     * 时间戳转时间字符串
     *
     * @param time 时间戳
     * @return String
     */
    public static String getDateString1(Long time) {
        SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_HOUR_MINUTE_SECOND);

        return sdf.format(time);
    }

    /**
     * 获得本周一0点时间
     *
     * @return date
     */
    public static Date getWeekmorning() {
        Calendar cal = Calendar.getInstance();
        int day = -(cal.get(Calendar.DAY_OF_WEEK) - 2);
        if (cal.get(Calendar.DAY_OF_WEEK) == 1) {
            day = -6;
        }
        cal.add(Calendar.DAY_OF_WEEK, -(cal.get(Calendar.DAY_OF_WEEK) - 7));
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /***
     * 根据当前时间获取本周第一天0点
     *
     * @param date 日期
     * @return date
     */
    public static Date getWeekmorning(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int day = -(cal.get(Calendar.DAY_OF_WEEK) - 2);
        if (cal.get(Calendar.DAY_OF_WEEK) == 1) {
            day = -6;
        }
        cal.add(Calendar.DAY_OF_WEEK, day);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /***
     * 根据当前时间获取本周最后一天时间的23:59:59
     *
     * @return date
     */
    public static Date getWeeknight() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getWeekmorning());
        cal.add(Calendar.DAY_OF_WEEK, 6);
        cal.add(Calendar.HOUR_OF_DAY, 23);
        cal.add(Calendar.MINUTE, 59);
        cal.add(Calendar.SECOND, 59);
        cal.set(Calendar.MILLISECOND, 999);
        return cal.getTime();
    }

    /***
     * 根据当前时间获取本周最后一天时间的23:59:59
     *
     * @param date 日期
     * @return date
     */
    public static Date getWeeknight(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getWeekmorning(date));
        cal.add(Calendar.DAY_OF_WEEK, 6);
        cal.add(Calendar.HOUR_OF_DAY, 23);
        cal.add(Calendar.MINUTE, 59);
        cal.add(Calendar.SECOND, 59);
        cal.set(Calendar.MILLISECOND, 999);
        return cal.getTime();
    }

    /***
     * 获得本月第一天0点时间
     *
     * @return date
     */
    public static Date getBeginDayOfMonth() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /***
     * 获得时间所在月份第一天0点时间
     *
     * @return date
     */
    public static Date getBeginDayOfMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /***
     * 获得本月最后一天23:59:59
     *
     * @return date
     */
    public static Date getEndDayOfMonth() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        cal.set(Calendar.MILLISECOND, 999);
        return cal.getTime();
    }

    /***
     * 获取时间所在月份最后一天23:59:59
     *
     * @return date
     */
    public static Date getEndDayOfMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        cal.set(Calendar.MILLISECOND, 999);
        return cal.getTime();
    }

    /**
     * 递归取时间集合(yyyy-MM-dd)
     * @param dateTimeStar
     * @param dateTimeStop
     * @return
     */
    public static ArrayList<String> getDateList(String dateTimeStar, String dateTimeStop, ArrayList<String> arrDate){
        Calendar star= Calendar.getInstance();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

        Date starDate =DateUtils.convert(dateTimeStar);
        Date stopDate =DateUtils.convert(dateTimeStop);
        star.setTime(stopDate);

        if(!starDate.equals(stopDate)){
            arrDate.add(formatter.format(star.getTime()));
            star.add(Calendar.DATE, -1);
            getDateList(dateTimeStar,formatter.format(star.getTime()),arrDate);
        }else{
            arrDate.add(formatter.format(star.getTime()));
        }

        return arrDate;
    }



    /****
     * 时间转String
     * @param date 日期
     * @param format 格式
     * @return
     */
    public static String dateToString(Date date, String format) {
        if (date == null) {
            return null;
        }
        if (StringUtils.hasText(format)) {
            format = FORMAT_YEAR_MONTH_DAY;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }

    /**
     * 设置时间
     * @param date  日期
     * @param calendarField  类型
     * @param amount  设置数
     **/
    private static Date set(Date date, int calendarField, int amount) {
        if (date == null) {
            return null;
        }
        final Calendar c = Calendar.getInstance();
        c.setLenient(false);
        c.setTime(date);
        c.set(calendarField, amount);
        return c.getTime();
    }

    /**
     * 设置当前时间的年数
     * @param date  日期
     * @param amount  设置数
     **/
    public static Date setYears(Date date, int amount) {
        return set(date, Calendar.YEAR, amount);
    }

    /**
     * 设置当前时间的月数
     * @param date  日期
     * @param amount  设置数
     **/
    public static Date setMonths(Date date, int amount) {
        return set(date, Calendar.MONTH, amount);
    }

    /**
     * 设置当前时间的日数
     * @param date  日期
     * @param amount  设置数
     **/
    public static Date setDays(Date date, int amount) {
        return set(date, Calendar.DAY_OF_MONTH, amount);
    }

    /**
     * 设置当前时间的小时数
     * @param date  日期
     * @param amount  设置数
     **/
    public static Date setHours(Date date, int amount) {
        return set(date, Calendar.HOUR_OF_DAY, amount);
    }

    /**
     * 设置当前时间的分钟数
     * @param date  日期
     * @param amount  设置数
     **/
    public static Date setMinutes(Date date, int amount) {
        return set(date, Calendar.MINUTE, amount);
    }

    /**
     * 设置当前时间的秒数
     * @param date  日期
     * @param amount  设置数
     **/
    public static Date setSeconds(Date date, int amount) {
        return set(date, Calendar.SECOND, amount);
    }

    /**
     * 设置当前时间的毫秒数
     * @param date  日期
     * @param amount  设置数
     **/
    public static Date setMilliseconds(Date date, int amount) {
        return set(date, Calendar.MILLISECOND, amount);
    }

    /**
     * 将 Date 转为 LocalDate
     *
     * @param date 日期
     * @return java.time.LocalDate;
     */
    public static LocalDate dateToLocalDate(Date date) {
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * 收集起始时间到结束时间之间所有的时间并以字符串集合方式返回
     * @param start
     * @param end
     * @return
     */
    public static List<String> collectDates(LocalDate start, LocalDate end){
        // 用起始时间作为流的源头，按照每次加一天的方式创建一个无限流
        return Stream.iterate(start, localDate -> localDate.plusDays(1))
        // 截断无限流，长度为起始时间和结束时间的差+1个
            .limit(ChronoUnit.DAYS.between(start, end) + 1)
        // 由于最后要的是字符串，所以map转换一下
            .map(LocalDate::toString)
        // 把流收集为List
            .collect(Collectors.toList());
    }

    /**
     * 收集起始时间到结束时间之间所有的时间并以字符串集合方式返回
     * @param start
     * @param end
     * @return
     */
    public static List collectDates(Date start, Date end){

        return collectDates(dateToLocalDate(start), dateToLocalDate(end));
    }

    /**
     * 将 LocalDateTime 转换成 Date
     *
     * @param date LocalDateTime
     * @return LocalDateTime
     */
    public static Date of(LocalDateTime date) {
        if (date == null) {
            return null;
        }
        // 将此日期时间与时区相结合以创建 ZonedDateTime
        ZonedDateTime zonedDateTime = date.atZone(ZoneId.systemDefault());
        // 本地时间线 LocalDateTime 到即时时间线 Instant 时间戳
        Instant instant = zonedDateTime.toInstant();
        // UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
        return Date.from(instant);
    }

    /**
     * 将 Date 转换成 LocalDateTime
     *
     * @param date Date
     * @return LocalDateTime
     */
    public static LocalDateTime of(Date date) {
        if (date == null) {
            return null;
        }
        // 转为时间戳
        Instant instant = date.toInstant();
        // UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    }
}
